home *** CD-ROM | disk | FTP | other *** search
- (*
-
- Personal Pascal routine to convert REALS to STRINGS,
- by
- Doug Harrison, PPN 72277,2315.
-
- Please send any comments, friendly criticisms, etc. to me. I've used
- this routine extensively and have found no bugs in this version to
- date. Compile it and declare it EXTERNAL in your program, and specify
- it as an additional link file, or simply include the procedure as is,
- after removing the compiler directives and dummy program shell.
- REAL_TO_STRING allows one to state the number of digits to be displayed
- right of the decimal and whether or not to express the string in
- scientific notation or in expanded form, i.e. 2e22 = 2 followed by 22
- zeroes. Enjoy!
-
- *)
-
-
- {$M+}
- {$E+}
- PROGRAM mock;
-
- PROCEDURE REAL_TO_STRING ( real_num : REAL;
- VAR string_real : STRING;
- digits : INTEGER;
- sci_not : BOOLEAN );
-
- (* real_num : real number to be converted into a string
- string_real : working variable that also passes string result to caller
- digits : specifies # of digits to be displayed right of decimal,
- valid values are 0-8
- sci_not : flag which determines whether to express in sci. not. or not
- *)
-
- (* FORMAT of string returned is:
- sci. not.:
- sign ( - or SPACE ), #.#####... , E, sign ( - or nothing ), ##.
- non-sci. not. :
- sign ( - or SPACE ), ####.####.
- *)
-
- (* Round-off errors of the nature x.xxxxxxx999 are corrected; consequently,
- any number with a sequence of 3 or more terminal 9's
- is affected, even if this is NOT an artifact. This should rarely be a
- problem. Also, if a number is to be expressed in expanded form, the
- magnitude of the exponent plus the # of digits to be displayed can not
- exceed 8, since LONG_ROUND generates long_ints- size < 2e9. This is not
- too severe a problem since only 11 digits of precision are supported
- anyway. That is, specifying 4 digits for the # 100,000,000.9012 is
- meaningless since the number is rounded to 100,000,000.9 as it becomes
- a REAL. The last digits are unavailable to real_to_string. In such
- cases, no action is performed on the number- it emerges untouched by
- the rounding function. Also, note that the detection of 999 occurs after
- conversion to 1 <= mag_num < 10. Thus, 99,999,999,999 becomes 9.9999999999
- which indicates a rounding error.
- *)
-
- TYPE STR1 = STRING [ 1 ];
-
- VAR mag_num : REAL;
- c ,i , j, len,
- start_delete,
- end_delete : INTEGER;
- sign_exp : STR1;
- temp : STRING;
- found : BOOLEAN;
- last : ARRAY [ 1..11 ] OF STR1;
-
-
-
- PROCEDURE ADJUST_TO_SPECIFIED_PRECISION;
-
- (* adjusts appearance following rounding *)
-
- VAR dec_pos : INTEGER;
-
- BEGIN
-
- dec_pos := POS ( '.' , string_real );
- WHILE LENGTH ( string_real ) < dec_pos + digits DO
- string_real := CONCAT ( string_real , '0' );
- WHILE LENGTH ( string_real ) > dec_pos + digits DO
- DELETE ( string_real , LENGTH ( string_real ) , 1 );
- IF POS ( '.' , string_real ) = LENGTH ( string_real )
- THEN DELETE ( string_real , LENGTH ( string_real ) , 1 );
-
- END; (* adjust_to_specified_precision *)
-
-
-
- PROCEDURE SUCCESSOR ( VAR num : STR1 );
-
- (* used to "increment" a string digit *)
-
- BEGIN
- IF num = '8'
- THEN num := '9';
- IF num = '7'
- THEN num := '8';
- IF num = '6'
- THEN num := '7';
- IF num = '5'
- THEN num := '6';
- IF num = '4'
- THEN num := '5';
- IF num = '3'
- THEN num := '4';
- IF num = '2'
- THEN num := '3';
- IF num = '1'
- THEN num := '2';
- IF num = '0'
- THEN num := '1';
- END; (* SUCCESSOR *)
-
-
-
- BEGIN (* REAL_TO_STRING *)
-
- IF real_num <> 0.0 (* necessary for conversion to #.######### format *)
- THEN BEGIN
- IF real_num < 0.0 (* sign of number *)
- THEN string_real := '-'
- ELSE string_real := ' ';
- mag_num := ABS (real_num); (* got sign, so work with number
- magnitude ! *)
- c := 0; (* c counts the number of times the
- number can be multiplied or div-
- ided by 10 so that finally
- 1 <= number < 10 *)
- IF mag_num >= 10.0 (* make 1 <= number < 10, can't do
- if number = 0! *)
- THEN REPEAT
- mag_num := mag_num / 10.0;
- c := c+1;
- UNTIL mag_num < 10.0
- ELSE IF mag_num < 1.0
- THEN REPEAT
- mag_num := mag_num * 10.0;
- c := c+1;
- UNTIL mag_num >= 1.0;
-
- (* Round mag_num to specified # of digits *)
-
- IF ( sci_not ) AND ( digits <= 8 )
- THEN mag_num := LONG_ROUND ( mag_num * PwrOfTen ( digits ) ) /
- PwrOfTen ( digits );
-
- IF ( NOT sci_not ) AND ( ( c + digits ) <= 8 )
- THEN mag_num := LONG_ROUND ( mag_num * PwrOfTen ( c+ digits ) ) /
- PwrOfTen ( c + digits );
-
- (* reals have 11 digits of precision *)
- (* convert REAL to a string equivalent *)
-
- FOR i := 1 TO 11 DO
- BEGIN
- j := TRUNC (mag_num);
- string_real := CONCAT ( string_real , CHR ( j + 48 ));
- mag_num := ( mag_num - j ) * 10.0;
- IF i = 1
- THEN string_real := CONCAT ( string_real , '.' );
- END; (* FOR i *)
-
- IF (( real_num < 1.0 ) AND ( real_num > 0.0 )) OR
- (( real_num < 0.0 ) AND ( real_num > -1.0 ))
- THEN sign_exp := '-'
- ELSE sign_exp := '';
-
-
- (* Get rid of artifactual "999" generated, if any *)
-
- temp := COPY ( string_real , 4 , 10 );
-
- i := 10;
- found := FALSE;
-
- WHILE ( NOT found ) AND ( i >= 1 ) DO
- IF temp [ i ] <> '9'
- THEN found := TRUE
- ELSE i := i - 1;
- i := i + 1;
-
- IF i <= 8
- THEN BEGIN
-
- FOR j := 1 TO 10 DO
- last [ j ] := 'f';
-
- DELETE ( string_real ,i + 3, LENGTH(string_real)-(i+2) );
- len := LENGTH ( string_real );
- FOR i := 1 TO len DO
- last [ i ] := COPY ( string_real , i , 1 );
- IF len = 3 (* x.9999999999 *)
- THEN BEGIN
- IF last [ 2 ] = '9'
- THEN BEGIN
- last [ 2 ] := '1';
- last [ 4 ] := '0';
- IF sign_exp = ''
- THEN c := c + 1
- ELSE c := c - 1;
- END
- ELSE BEGIN
- successor ( last [ 2 ] );
- last [ 4 ] := '0';
- END;
- END
- ELSE successor ( last [ len ] ); (* x.xxxx999999 *)
- (* needn't check here if last[len]=9; it CAN'T be,
- as it would have been a part of the string of 9's
- *)
-
- string_real := '';
- i := 1;
-
- WHILE ( last [ i ] <> 'f' ) AND ( i < 11 ) DO
- (* recreate string_real *)
- BEGIN
- string_real := CONCAT ( string_real , last [ i ] );
- i := i + 1;
- END;
-
- END; (* then of 999999 routine *)
-
-
-
- IF NOT sci_not (* express in expanded form *)
- THEN IF sign_exp = '-' (* mag_num < 1, mag_num <> 0 *)
- THEN BEGIN
- temp := COPY ( string_real , 1 , 1 );
- temp := CONCAT ( temp , '0.' );
- FOR i := 1 TO c - 1 DO
- temp := CONCAT ( temp , '0' );
- DELETE ( string_real , 1 , 1 );
- DELETE ( string_real , 2 , 1 );
- string_real := CONCAT ( temp , string_real );
- END
- ELSE BEGIN
- DELETE ( string_real , 3 , 1 );
- IF ( 3 + c ) > LENGTH ( string_real )
- THEN FOR i := LENGTH( string_real ) TO ( 2 + c ) DO
- string_real := CONCAT ( string_real ,
- '0' );
- INSERT ( '.' , string_real , 3 + c );
- adjust_to_specified_precision;
- END
- ELSE BEGIN (* express in scientific notation *)
- temp := '';
- IF c >= 30
- THEN BEGIN
- temp := '3';
- c := c - 30;
- END;
- IF c >= 20
- THEN BEGIN
- temp := '2';
- c := c - 20;
- END;
- IF c >= 10
- THEN BEGIN
- temp := '1';
- c := c - 10;
- END;
- temp := CONCAT ( temp , CHR ( c + 48 ) );
-
- adjust_to_specified_precision;
-
- string_real := CONCAT ( string_real , 'E' ,
- sign_exp , temp );
- END;
- END (* begin of first then clause *)
-
- ELSE BEGIN (* real_num = 0 *)
-
- string_real := ' 0';
- FOR i := 1 to digits DO
- BEGIN
-
- IF i = 1
- THEN string_real := CONCAT ( string_real , '.' );
- string_real := CONCAT ( string_real , '0' );
-
- END;
- END;
-
- END; (* REAL_TO_STRING *)
- BEGIN (* Dummy program for modular compilation *)
- END.
-